xc_resume: fix modify_returncode when host width != guest width
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 4 Nov 2009 22:32:01 +0000 (22:32 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 4 Nov 2009 22:32:01 +0000 (22:32 +0000)
Also improve checking in xc_domain_resume_any().

Signed-off-by: Brendan Cully <brendan@cs.ubc.ca>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
tools/libxc/xc_resume.c

index 73c2904053e922f7c229ba6947fe5b7aea58c8c4..ad0f137b0d5ee050a9c5dd9c8a5da4790f4d051a 100644 (file)
@@ -8,15 +8,25 @@
 #include <xen/foreign/x86_64.h>
 #include <xen/hvm/params.h>
 
-/* Don't yet support cross-address-size uncooperative resume */
-#define guest_width (sizeof (unsigned long))
+static int pv_guest_width(int xc_handle, uint32_t domid)
+{
+    DECLARE_DOMCTL;
+    domctl.domain = domid;
+    domctl.cmd = XEN_DOMCTL_get_address_size;
+    if ( xc_domctl(xc_handle, &domctl) != 0 )
+    {
+        PERROR("Could not get guest address size");
+        return -1;
+    }
+    return domctl.u.address_size.size / 8;
+}
 
 static int modify_returncode(int xc_handle, uint32_t domid)
 {
     vcpu_guest_context_any_t ctxt;
     xc_dominfo_t info;
     xen_capabilities_info_t caps;
-    int rc;
+    int rc, guest_width;
 
     if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 )
     {
@@ -24,30 +34,34 @@ static int modify_returncode(int xc_handle, uint32_t domid)
         return -1;
     }
 
-    /* HVM guests without PV drivers do not have a return code to modify. */
     if ( info.hvm )
     {
+        /* HVM guests without PV drivers have no return code to modify. */
         unsigned long irq = 0;
         xc_get_hvm_param(xc_handle, domid, HVM_PARAM_CALLBACK_IRQ, &irq);
         if ( !irq )
             return 0;
-    }
 
-    if ( xc_version(xc_handle, XENVER_capabilities, &caps) != 0 )
+        /* HVM guests have host address width. */
+        if ( xc_version(xc_handle, XENVER_capabilities, &caps) != 0 )
+        {
+            PERROR("Could not get Xen capabilities\n");
+            return -1;
+        }
+        guest_width = strstr(caps, "x86_64") ? 8 : 4;
+    }
+    else
     {
-        PERROR("Could not get Xen capabilities\n");
-        return -1;
+        /* Probe PV guest address width. */
+        guest_width = pv_guest_width(xc_handle, domid);
+        if ( guest_width < 0 )
+            return -1;
     }
 
     if ( (rc = xc_vcpu_getcontext(xc_handle, domid, 0, &ctxt)) != 0 )
         return rc;
 
-    if ( !info.hvm )
-        ctxt.c.user_regs.eax = 1;
-    else if ( strstr(caps, "x86_64") )
-        ctxt.x64.user_regs.eax = 1;
-    else
-        ctxt.x32.user_regs.eax = 1;
+    SET_FIELD(&ctxt, user_regs.eax, 1);
 
     if ( (rc = xc_vcpu_setcontext(xc_handle, domid, 0, &ctxt)) != 0 )
         return rc;
@@ -88,6 +102,7 @@ static int xc_domain_resume_any(int xc_handle, uint32_t domid)
     xc_dominfo_t info;
     int i, rc = -1;
 #if defined(__i386__) || defined(__x86_64__)
+    int guest_width;
     unsigned long mfn, p2m_size = 0;
     vcpu_guest_context_any_t ctxt;
     start_info_t *start_info;
@@ -113,6 +128,13 @@ static int xc_domain_resume_any(int xc_handle, uint32_t domid)
         return rc;
     }
 
+    guest_width = pv_guest_width(xc_handle, domid);
+    if ( guest_width != sizeof(long) )
+    {
+        ERROR("Cannot resume uncooperative cross-address-size guests");
+        return rc;
+    }
+
     /* Map the shared info frame */
     shinfo = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
                                   PROT_READ, info.shared_info_frame);
@@ -167,7 +189,7 @@ static int xc_domain_resume_any(int xc_handle, uint32_t domid)
         goto out;
     }
 
-    mfn = ctxt.c.user_regs.edx;
+    mfn = GET_FIELD(&ctxt, user_regs.edx);
 
     start_info = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
                                       PROT_READ | PROT_WRITE, mfn);